(function(undefined) {
	/*
	 * Call this function on object to append Class and Namespace "keywords".
	 */
	var CClass = function() {
		/*
		 * Create or returns created class.
		 * 1. Use new (Class(string <ClassName>)), to construct an
		 * object of a class.
		 * 2. Use Class(string <ClassName>, function <Definition>) to create
		 * a class with no superclass.
		 * 3. Use Class(string <ClassName>, string|function <SuperClass>, function <Definition>)
		 * to create a class with super class.
		 * All other combination or arguments, creation of existing classes or
		 * missing superclass will throw an exception.
		 */
		this.Class = function() {
			if (arguments.length === 0) {
				throw new Exception('Invalid number of arguments: expected 1, 2 or 3, got 0.');
			}
			if (typeof(arguments[0]) !== 'string') {
				throw new Exception('Argument 1: expected string, got ' + typeof(arguments[0]));
			}
			if (arguments.length === 1) {
				if (!(classes[arguments[0]] instanceof Object)) {
					throw new Exception('Class with name "' + arguments[0] + '" does not exists.');
				}
				return classes[arguments[0]].construct;
			} else if (arguments.length === 2) {
				if (!(arguments[1] instanceof Function)) {
					throw new Exception('Arguments 2: expected function, got ' + typeof(arguments[1]));
				}
				if (classes[arguments[0]] instanceof Object) {
					throw new Exception('Class ' + arguments[0] + ' already exists in current namespace.');
				}
				_createClass(arguments[0], arguments[1]);
				return classes[arguments[0]].construct;
			} else if (arguments.length === 3) {
				if (!(arguments[2] instanceof Function)) {
					throw new Exception('Arguments 3: expected function, got ' + typeof(arguments[2]));
				}
				var baseName;
				if (arguments[1] instanceof Function) {
					for (var v in classes) {
						if (classes[v].construct === arguments[1] || classes[v].proto === arguments[1]) {
							baseName = v;
						}
					}
					if (!baseName) {
						throw new Exception('Cannot find base class for given function.');
					}
				} else if (typeof(arguments[1]) === 'string') {
					if (!classes[arguments[1]]) {
						throw new Exception('Cannot find base class: ' + arguments[1]);
					}
					baseName = arguments[1];
				} else {
					throw new Exception('Argument 2: expected string or function, got ' + typeof(arguments[1]));
				}
				if (classes[arguments[0]] instanceof Object) {
					throw new Exception('Class ' + arguments[0] + ' already exists in current namespace.');
				}
				_createClass(arguments[0], arguments[2], baseName);
				return classes[arguments[0]].construct;
			} else {
				throw new Exception('Invalid number of arguments: expected 1, 2 or 3, got ' + arguments.length + '.');
			}
		};
		/*
		 * Append the Class and Namespace "keywords" to a specific object or
		 * existing class in current namespace.
		 */
		this.Namespace = function(n) {
			if (typeof(n) === 'string') {
				if (!classes[n]) {
					throw new Exception('Class "' + n + '" not exists to be used as a namespace.');
				}
				CClass.call(classes[n].construct);
			} else if (n instanceof Object) {
				CClass.call(n);
			} else {
				throw new Exception('You should create namespace on existing class or object');
			}
		};
		//This holds an information about classes in current namespace.
		var classes = {};
		//Exception class to throw (not part of the namespace classes).
		var Exception = function(message) {
			var _message = message;
			this.getMessage = function() {
				return _message;
			};
			this.toString = function() {
				return 'CClass.Exception: ' + _message;
			};
		};
		//Change exception name to CClass.Exception
		Exception.toString = function() {
			return 'CClass.Exception';
		};
		/*
		 * The most important variable used when constructing prototype chain.
		 * With this we prevent any definition call, when we build the objects
		 * for prototype chain.
		 */
		var inheriting = false;
		var _createClass = function(name, proto, baseName) {
			var _objectParent;
			/*
			 * This is the actual class, we return. All object are actially
			 * instances of this function, but it is local variable, so
			 * every class receive different instance function. This causes some
			 * memory bottleneck, since every class created will create new
			 * such function.
			 */
			var Class = function() {
				if (!inheriting) {
					if (classes[classes[name].base] instanceof Object) {
						(function(baseData) {
							var _parent, _inherited = {}, that = this;
							/*
							 * Solution to problem 2
							 * Problem 2: When call the parent, it will receive its own "this",
							 * however current "this" will be unaffected, so we must transfer the
							 * differences that are not overriden.
							 * The problem is that each call to parent can make differences to parent object.
							 * We must transfer this differences for every function we call to parent. 
							 */
							var _diffThisToParent = function() {
								var v;
								for (v in _inherited) {
									if (!_parent.hasOwnProperty(v)) {
										if(this.hasOwnProperty(v)) {
											delete this[v];
										}
										_inherited[v] = undefined;
									} else if (_parent[v] !== _inherited[v]) {
										if (_parent[v] instanceof Function) {
											if (this[v] instanceof Function) {
												_inherited[v] = _parent[v];
											} else {
												(function(methodName) {
													this[methodName] = function() {
														var r = _parent[methodName].apply(_parent, arguments);
														_diffThisToParent.call(that);
														return r;
													};
													_inherited[methodName] = _parent[methodName];
												}).call(this, v);
											}
										} else {
											this[v] = _inherited[v] = _parent[v];
										}
									}
								}
								for (v in _parent) {
									if (!this.hasOwnProperty(v) && !_inherited.hasOwnProperty(v)) {
										//No property, apply it;
										if (_parent[v] instanceof Function) {
											(function(methodName) {
												this[methodName] = function() {
													var r = _parent[methodName].apply(_parent, arguments);
													_diffThisToParent.call(that);
													return r;
												};
												_inherited[methodName] = _parent[methodName];
											}).call(this, v);
										} else {
											this[v] = _inherited[v] = _parent[v];
										}
									}
								}
							};
							/*
							 * Solution to problem 3 (more expensive).
							 * Problem 3: If anything calls this.Parent.method() directly, it goes
							 * directly to the parent method, without any propagation. E.g. if your method override another
							 * and calls this.Parent.method(), changes to "this" in parent does not reflect in current.
							 * Solution is to use proxy method for all functions in parent. This doubles the call-stack.
							 */
							var _proxyParent = function(parent) {
								var child = this;
								for(var v in parent) {
									if(parent[v] instanceof Function) {
										(function(methodName) {
											var method = parent[methodName];
											parent[methodName] = function() {
												var r = method.apply(parent, arguments);
												_diffThisToParent.call(child);
												return r;
											};
										}).call(this, v);
									}
								}
							};
							this.Parent = _objectParent = function() {
								var v;
								/*
								 * Problem 1: We cannot specify argument as an Array, when constructing with new.
								 * Instead we create the object the way the new operator would do.
								 */
								_parent = new Object();
								for (v in baseData.construct.prototype) {
									_parent[v] = baseData.construct.prototype[v];
								}
								baseData.construct.apply(_parent, arguments);
								this.Parent = _parent;
								_proxyParent.call(this, this.Parent);
								_diffThisToParent.call(this);
							};
						}).call(this, classes[classes[name].base]);
					}
					this.constructor = classes[name].construct;
					this.toString = function() {
						return '[object ' + name + ']';
					};
					proto.apply(this, arguments);
					if((_objectParent instanceof Function) && (this.Parent === _objectParent)) {
						this.Parent(); //Default constructor call.
					}
				}
			};
			var _initPrototypeChain = function() {
				var classData = classes[name], chain = [], i;
				while (classData) {
					chain.push(classData.construct);
					classData = classes[classData.base];
				}
				for (i = chain.length - 1; i > 0; i--) {
					chain[i - 1].prototype = new chain[i]();
					chain[i - 1].prototype.constructor = chain[i - 1];
				}
			};
			classes[name] = {};
			classes[name].proto = proto;
			classes[name].construct = Class;
			Class.toString = function() {
				return name;
			};
			if (baseName) {
				classes[name].base = baseName;
				inheriting = true;
				_initPrototypeChain();
				inheriting = false;
			}
		};
	};
	CClass.call(window);
})();
